/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.loja.view.swing;

import br.com.loja.model.entity.Switchable;
import br.com.loja.model.service.factory.ServiceFactory;
import java.awt.Component;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;

/**
 *
 * @author DavidLuiz
 */
public abstract class AbstractComponentFactory {

    public static final int COMMOM_TYPE = 0;
    public static final int ENUM_TYPE = 1;
    public static final int AGGREGATION_TYPE = 2;
    public static final int COMPOSITION_TYPE = 3;
    protected final Field field;
    private final ServiceFactory serviceFactory;

    public AbstractComponentFactory(Field field, ServiceFactory serviceFactory) {
        this.field = field;
        this.serviceFactory = serviceFactory;
    }

    public Component getComponent() {
        int componentType = getComponentType(field);
        switch (componentType) {
            case COMMOM_TYPE:
                return buildCommonComponent(field, serviceFactory);
            case ENUM_TYPE:
                return buildEnumComponent(field, serviceFactory);
            case AGGREGATION_TYPE:
                return buildAggregationComponent(field, serviceFactory);
            case COMPOSITION_TYPE:
                return buildCompositionComponent(field, serviceFactory);
            default:
                return null;
        }
    }

    public int getComponentType() {
        return getComponentType(field);
    }

    protected abstract Component buildCompositionComponent(Field field, ServiceFactory serviceFactory);

    protected abstract Component buildAggregationComponent(Field field, ServiceFactory serviceFactory);

    protected abstract Component buildEnumComponent(Field field, ServiceFactory serviceFactory);

    protected abstract Component buildCommonComponent(Field field, ServiceFactory serviceFactory);

    protected boolean isToMany(Field field) {
        return Collection.class.isAssignableFrom(field.getType());
    }

    protected Class<?> getClassType(Field field) {
        if (isToMany(field)) {
            ParameterizedType listType = (ParameterizedType) field.getGenericType();
            return (Class<?>) listType.getActualTypeArguments()[0];
        } else {
            return field.getType();
        }
    }

    protected int getComponentType(Field field) {
        Class<?> type = getClassType(field);
        if (Switchable.class.isAssignableFrom(type)) {
            if (type.getAnnotation(Composition.class) != null) {
                if (type.getAnnotation(Composition.class).value().equals(field.getDeclaringClass())) {
                    return COMPOSITION_TYPE; // is Composition
                }
            }
            return AGGREGATION_TYPE; // is Aggregation
        } else if (type.isEnum()) {
            return ENUM_TYPE; // is Enum
        } else {
            return COMMOM_TYPE; // is Common
        }
    }

}
